﻿#include "dat.h"
#include <stdint.h>
#include <stdlib.h>

#ifdef _WIN32

static const int64_t kNumMillisecsPerSec = INT64_C(1000);
static const int64_t kNumMicrosecsPerSec = INT64_C(1000000);
static const int64_t kNumNanosecsPerSec = INT64_C(1000000000);

int64
nanoseconds(void)
{
	static volatile LONG last_timegettime = 0;
	static volatile int64_t num_wrap_timegettime = 0;

	int64_t ticks;
	volatile LONG* last_timegettime_ptr = &last_timegettime;
	DWORD now = timeGetTime();
	// Atomically update the last gotten time
	DWORD old = InterlockedExchange(last_timegettime_ptr, now);
	if (now < old) {
		// If now is earlier than old, there may have been a race between threads.
		// 0x0fffffff ~3.1 days, the code will not take that long to execute
		// so it must have been a wrap around.
		if (old > 0xf0000000 && now < 0x0fffffff) {
			num_wrap_timegettime++;
		}
	}
	ticks = now + (num_wrap_timegettime << 32);
	// TODO(deadbeef): Calculate with nanosecond precision. Otherwise, we're
	// just wasting a multiply and divide when doing Time() on Windows.
	ticks = ticks * kNumNanosecsPerSec / kNumMillisecsPerSec;

	return ticks;
}

#else

#include <sys/time.h>

int64
nanoseconds(void)
{
    int r;
    struct timeval tv;

    r = gettimeofday(&tv, 0);
    if (r != 0) return warnx("gettimeofday"), -1; // can't happen

    return ((int64)tv.tv_sec)*1000000000 + ((int64)tv.tv_usec)*1000;
}
#endif
